/**
 * creation: 12-apr-2007
 */
package org.jfonia.harmony;

import java.util.ArrayList;

import org.jfonia.pitch.MusicalInterval;
import org.jfonia.pitch.PitchNotationStyle;
import org.jfonia.pitch.StandardPitchNotationStyle;


/**
 * Provides standard chord style.
 * 
 * @author Wijnand
 *
 */
public class StandardChordNotationStyle implements ChordNotationStyle
{
	private final static PitchNotationStyle pitchNotationStyle = new StandardPitchNotationStyle();
	
	// helper:
	public String makeString(ChordAlteration chordAlteration)
	{
		int at = chordAlteration.getAlterationType();
		
		StringBuilder sb = new StringBuilder();
		if (at==ChordType.OMIT)
			sb.append('-');
		else if (at==ChordType.LOWERED)
			sb.append('b');
		else if (at==ChordType.RAISED)
			sb.append('#');
		else if (at==ChordType.DOUBLE_LOWERED)	// doesn't happen normally
			sb.append("bb");
		else
			sb.append("???");		// TODO: better treatment
		
		sb.append(Integer.toString(chordAlteration.getDegree()));
		
		return sb.toString();
	}
	
	public String makeString(ChordTypeNotation chordTypeNotation)
	{
		StringBuilder sb = new StringBuilder();
		sb.append(chordTypeNotation.getKind());
		
		ArrayList<ChordAlteration> altList = chordTypeNotation.getChordAlterationList();
		if (altList!=null && altList.size()>0)
		{
			sb.append('(');
			sb.append(makeString(altList.get(0)));
			for (int i=1; i<altList.size(); i++)
			{
				sb.append(',');
				sb.append(makeString(altList.get(i)));
			}
			sb.append(')');
		}
		return sb.toString();
	}

	public String makeString(MusicalInterval rootPitchClass, ChordTypeNotation chordTypeNotation, MusicalInterval bassPitchClass)
	{
		StringBuilder sb = new StringBuilder();
		sb.append(pitchNotationStyle.getReducedName(rootPitchClass));
		
		sb.append(makeString(chordTypeNotation));
		
		if (rootPitchClass.equals(bassPitchClass))
		{
			sb.append('/');
			sb.append(pitchNotationStyle.getReducedName(bassPitchClass));
		}
		return sb.toString();
	}

	/**
	 * mimics MusicXML Dolet to produce chord-name and alteration-lists.
	 * Simplification: kind is based on third and seventh, with the exception of sus and 6 chords -
	 *  all the rest via alterations...
	 */
	 // TODO: see what happens if feeded back into Sibelius/Finale...
	 // TODO: return "other" plus alterations in case of strange stuff, instead of exception
	public ChordTypeNotation makeTypeNotation(ChordType chordType)
	{
		String kind = "";
		ArrayList<ChordAlteration> chordAlterationList = new ArrayList<ChordAlteration>();
		
		if (chordType==null)	// no chord
			return new ChordTypeNotation("none", chordAlterationList);
		
		int ct3 = chordType.getType3(); 
		int ct5 = chordType.getType5();
		int ct7 = chordType.getType7(); 
		int ct9 = chordType.getType9(); 
		int ct11 = chordType.getType11();
		int ct13 = chordType.getType13(); 
		boolean omit3explicitly = false;	
		boolean alter5explicitly = false;
		
		if (ct5==ChordType.PERFECT)
		{
			if (ct3==ChordType.MAJOR)
			{
				if (ct7==ChordType.OMIT)	
				{
					if (ct13==ChordType.PERFECT)
					{
						kind = "major-sixth";
						ct13 = ChordType.OMIT;	// suppress
					}		
					else
						kind = "major";
				}
				else if (ct7==ChordType.MAJOR)	
					kind = "major-seventh";
				else if (ct7==ChordType.MINOR)	
				{
					if (ct9==ChordType.MAJOR)
					{
						if (ct11==ChordType.PERFECT)
						{
							if (ct13==ChordType.MAJOR) 
							{
								kind = "dominant-13th";
								ct13 = ChordType.OMIT;
							}
							else
								kind = "dominanth-11th";
							ct11 = ChordType.OMIT;
						}
						else
							kind = "dominant-ninth";
						ct9 = ChordType.OMIT;
					}
					else
						kind = "dominant";
					
				}
				else 
					throw new RuntimeException("unexpected alteration of seventh degree: " + ct7);
				
			}
			else if (ct3==ChordType.MINOR)
			{
				if (ct7==ChordType.OMIT)	
				{
					if (ct13==ChordType.PERFECT)
					{
						kind = "minor-sixth";
						ct13 = ChordType.OMIT;
					}	
					else
						kind = "minor";
						
				}
				else if (ct7==ChordType.MAJOR)	
					kind = "minor-major";
				else if (ct7==ChordType.MINOR)	
				{
					if (ct9==ChordType.MAJOR)
					{
						if (ct11==ChordType.PERFECT)
						{
							if (ct13==ChordType.MAJOR)
							{
								kind = "minor-13th";
								ct13 = ChordType.OMIT;
							}
							else
								kind = "minor-11th";
							ct11 = ChordType.OMIT;
						}
						else
							kind = "minor-ninth";
						ct9 = ChordType.OMIT;
					}
					else
						kind = "minor-seventh";
				}
				else
						throw new RuntimeException("unexpected alteration of seventh degree: " + ct7);
				
			}
			else if (ct3==ChordType.OMIT)
			{
				if (ct11==ChordType.PERFECT)
				{
					kind = "suspended-fourth";
					ct11 = ChordType.OMIT;
				}
				else if (ct11==ChordType.OMIT)
				{
					if (ct9==ChordType.MAJOR)
					{
						kind = "suspended-second"; 	
						ct9 = ChordType.OMIT;
					}
					else
					{
						kind = "power";   
						omit3explicitly = true;
					}
				}
					
			}
			else
				throw new RuntimeException("unexpected alteration of third degree: " + ct3);
		}
		else if (ct5==ChordType.LOWERED) 
		{
			if (ct3==ChordType.MINOR)
			{
				if (ct7==ChordType.LOWERED)	
					kind = "half-diminished";
				else if (ct7==ChordType.DOUBLE_LOWERED)	
					kind = "diminished-seventh";
				else if (ct7==ChordType.OMIT)
					kind = "diminished";
				else
					throw new RuntimeException("unexpected alteration of seventh degree: " + ct7);
			}
			else if (ct3==ChordType.MAJOR)
			{
				alter5explicitly = true;
				if (ct7==ChordType.LOWERED)
					kind = "dominant-seventh";	// b5
				else 
					throw new RuntimeException("unexpected alteration of seventh degree: " + ct7);
			}
			else 
				throw new RuntimeException("unexpected alteration of third degree: " + ct3);
		}
		else if (ct5==ChordType.RAISED)
		{
			if (ct3==ChordType.MAJOR)
			{
				if (ct7==ChordType.LOWERED)
					kind = "augmented-seventh";
				else if (ct7==ChordType.OMIT)
					kind = "augmented";
				else
					throw new RuntimeException("unexpected alteration of seventh degree: " + ct7);
			}
			else
				throw new RuntimeException("unexpected alteration of third degree: " + ct3);
		}
		else if (ct5!=ChordType.OMIT)
			throw new RuntimeException("unexpected alteration of fifth degree: " + ct5);
		
		if (omit3explicitly)
			chordAlterationList.add(new ChordAlteration(3, ChordType.OMIT));
		
		if (alter5explicitly && ct5!=ChordType.PERFECT)	
			chordAlterationList.add(new ChordAlteration(5, ct5));
		
		// seventh: suppressed
		
		if (ct9!=ChordType.OMIT)
		{
			if (ct9==ChordType.LOWERED_AND_RAISED)
			{
				chordAlterationList.add(new ChordAlteration(9, ChordType.LOWERED));
				chordAlterationList.add(new ChordAlteration(9, ChordType.RAISED));
			}	
			else 
				chordAlterationList.add(new ChordAlteration(9, ct9));
		}
		
		if (ct11!=ChordType.OMIT)
			chordAlterationList.add(new ChordAlteration(11, ct11));
		
		
		if (ct13!=ChordType.OMIT)
			chordAlterationList.add(new ChordAlteration(13, ct13));
			
		return new ChordTypeNotation(kind, chordAlterationList);
	}

	
}
